﻿#region

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Windows.Browser;
using Radovici.SharedLibrary;
using Radovici.SharedLibrary.Javascript;

#endregion

namespace Radovici.Ctrls.Facebook
{
    [ScriptableType]
    public partial class FacebookApi : Notifiable
    {
        #region Static constructor (tryTo initialize javascript FacebookApi)

//        static FacebookApi()
//        {
//            HtmlDocument doc = HtmlPage.Document;
//            var body = doc.GetElementsByTagName("body")[0] as HtmlElement;
//            if (body != null)
//            {
//                string fbScriptsHtml = "<script type=\"text/javascript\" src=\"http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php\"></script>" +
//                    "<script type=\"text/javascript\">FB.init(\"5716ce903d9a344ce4f5a1c6491ba3ae\", \"xd_receiver.htm\");</script>";
//                HtmlElement fbScripts = doc.CreateElement("div");
//                fbScripts.SetAttribute("innerHTML", fbScriptsHtml);
//                body.AppendChild(fbScripts);

//                //<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script>
//                HtmlElement include = doc.CreateElement("script");
//                include.SetAttribute("type", "text/javascript");
//                include.SetAttribute("src", "http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php");
//                body.AppendChild(include, body.Children[0] as HtmlElement);

//                //<script type="text/javascript">
//                //    FB.init("5716ce903d9a344ce4f5a1c6491ba3ae", "xd_receiver.htm");
//                //</script>
//                HtmlElement init = doc.CreateElement("script");
//                init.SetAttribute("type", "text/javascript");
//                init.SetProperty("innerHTML", "FB.init('5716ce903d9a344ce4f5a1c6491ba3ae', 'xd_receiver.htm');");
//                body.AppendChild(init);

//                HtmlPage.Window.Eval(string.Format(@"
//                (
//                function() 
//                {{
//                    var ref = document.createElement('script')
//                    ref.setAttribute(""type"", ""text/javascript"")
//                    ref.setAttribute(""src"", ""http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"")
//                }}
//                )()"));
//            }
//        }

        #endregion

        #region Private static fields

        private static readonly Dictionary<string, FacebookApi> _apis = new Dictionary<string, FacebookApi>();

        #endregion

        private string PluginId
        {
            get { return _pluginId; }
        }

        public FacebookUser User
        {
            get { return _user; }
        }

        private string UserId
        {
            get
            {
                object obj = JavascriptInterop.Eval("FB.Facebook.apiClient.get_session().uid;");
                return obj == null || obj is ScriptObject ? null : obj.ToString();
            }
        }

        public bool IsLoggedIn
        {
            get
            {
                if (IsInitialized)
                {
                    object obj = JavascriptInterop.Eval("FB.Facebook.apiClient.get_session();");
                    return obj != null;
                }
                return false;
            }
        }

        public static FacebookApi GetFacebookApi(string apiKey)
        {
            if (!_apis.ContainsKey(apiKey))
            {
                lock (_apis)
                {
                    if (!_apis.ContainsKey(apiKey))
                    {
                        _apis[apiKey] = new FacebookApi(apiKey);
                    }
                }
            }
            return _apis[apiKey];
        }

        public FacebookUser GetUser(string facebookUserId)
        {
            if (_user != null)
            {
                if (_user.UserId == facebookUserId)
                {
                    return _user;
                }
                return _user.Friends.SingleOrDefault(user => user.UserId == facebookUserId) ?? FacebookUser.DefaultUser;
            }
            return FacebookUser.DefaultUser;
        }

        private string ConvertDictionaryToJason(IDictionary<string, string> data)
        {
            string jason = string.Empty;
            foreach (string key in data.Keys)
            {
                if (!string.IsNullOrEmpty(jason))
                {
                    jason += ",";
                }
                jason += string.Format("\"{0}\":\"{1}\"", key, data[key]);
            }
            jason = "{" + jason + "}";
            return jason;
        }

        public void Publish(long bundleId, IDictionary<string, string> data)
        {
            string jason = ConvertDictionaryToJason(data);
            JavascriptInterop.Call(string.Format(
                    @"
FB.Facebook.apiClient.feed_publishUserAction({1}, {2}, [], 'body', 1, 'published wessage', function(success) {{ $get('{0}').Content.FacebookApi.PublishCallback(success) }});",
                    _pluginId, bundleId, jason));
        }

        [ScriptableMember]
        public void PublishCallback(object published)
        {
            Debug.WriteLine(string.Format("FacebookApi:PublishCallback({0})", published));
        }

        #region Login javascript interop

        public void Login()
        {
            JavascriptInterop.Call(string.Format("FB.Connect.requireSession($get('{0}').Content.FacebookApi.LoginCallback());", _pluginId));
        }

        [ScriptableMember]
        public void LoginCallback()
        {
            Debug.WriteLine("FacebookApi.LoginCallback()"); //NotifyLogin(); //NOTE: Meaningless callback (from facebook)
        }

        #endregion

        #region Logout javascript interop

        public void Logout()
        {
            JavascriptInterop.Call(
                string.Format(
                    @"
    FB.Connect.logout
    (
        function(success) {{ $get('{0}').Content.FacebookApi.LogoutCallback(success) }}    
    );",
                    _pluginId));
        }

        [ScriptableMember]
        public void LogoutCallback(bool success)
        {
            if (success)
            {
                _user = FacebookUser.DefaultUser;
                _loginTmr.Change(0, 2500);
                NotifyLogin();
            }
        }

        #endregion

        #region Private methods

        private readonly object _lock = new object();

        private bool IsInitialized
        {
            get
            {
                object obj = JavascriptInterop.Eval("FB != null && FB.Facebook != null && FB.Facebook.apiClient != null");
                return Convert.ToBoolean(obj);
            }
        }

        private void NotifyLogin()
        {
            Notify("User");
            Notify("IsLoggedIn");
        }


        private void LoginTimerCallback(object state)
        {
            if (IsLoggedIn)
            {
                _loginTmr.Change(int.MaxValue, int.MaxValue);
                lock (_lock)
                {
                    if (_user.UserId != UserId)
                    {
                        _user = new FacebookUser(this);
                        _user.PropertyChanged += OnUserPropertyChanged;
                    }
                }
                NotifyLogin();
            }
        }

        private void OnUserPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName) //HACK: Propertyly setup bindings remove the need for this.
            {
                case "Friends":
                    Notify("User.Friends");
                    break;
            }
        }

        #endregion

        #region Private fields

        private readonly Timer _loginTmr;
        private readonly string _pluginId = HtmlPage.Plugin.Id;
        private FacebookUser _user;

        #endregion

        #region Private constructor

        private FacebookApi(string apiKey)
        {
            //TODO: Consider using javascript Interop
            HtmlPage.Window.Eval(string.Format(
                                     @"
(
function() 
{{
    FB.init('{0}', 'xd_receiver.htm');
}}
)()", apiKey));
            HtmlPage.RegisterScriptableObject("FacebookApi", this);
            _loginTmr = new Timer(LoginTimerCallback, null, 0, 2500);
            _user = FacebookUser.DefaultUser;
        }

        #endregion
    }
}